
import os, sys
from itertools import starmap

from tools.utils.codegen import return_dict, scrunch_filename


#====================================================================

def read(*args):
    f = open(os.path.join(*args))
    try:
        return f.read()
    finally:
        f.close()


#====================================================================

def read_lines(*args):
    f = open(os.path.join(*args))
    try:
        return filter(None, [l.split('#')[0].strip() for l in f.readlines()])
    finally:
        f.close()


#====================================================================

def read_set(*args):
    return set(read_lines(*args))


#====================================================================

def _forever_split(s):
    for part in s.split():
        yield part
    while True:
        yield ''

def read_cols(dir_, name, cols):
    columns = cols.split()
    def extract(line):
        return dict(zip(columns, _forever_split(line)))
    return map(extract, read_lines(dir_, name))


#===============================================================================

def _eval_kwargs_column(container, context=None):
    if not container:
        return {}
    str_, ctx = container[0], {}
    if context is not None:
        ctx = __import__(context, fromlist=['*']).__dict__
    return eval(str_, ctx)

def read_args_kwargs(dir_, name, argcount, context=None):
    def _get_args_kwargs(line):
        args_kwargs = line.split(None, argcount)
        args = args_kwargs[:argcount]
        kwargs = _eval_kwargs_column(args_kwargs[argcount:], context)
        return args, kwargs
    return map(_get_args_kwargs, read_lines(dir_, name))


#===============================================================================
# ugly but helpful

def _ignore_gccxml_settings(f):
    # we only care about reading, not generating
    def g(*args, **kwargs):
        from pygccxml.parser.config import gccxml_configuration_t
        orig = gccxml_configuration_t.raise_on_wrong_settings
        gccxml_configuration_t.raise_on_wrong_settings = lambda _: None
        try:
            return f(*args, **kwargs)
        finally:
            gccxml_configuration_t.raise_on_wrong_settings = orig
    return g

@_ignore_gccxml_settings
def read_gccxml(*args):
    path = os.path.join(*args)
    from pygccxml.parser.config import config_t
    from pygccxml.parser.source_reader import source_reader_t
    return source_reader_t(config_t()).read_xml_file(path)[0]


#==========================================================================

BADGE = (
    'This file was generated by running the following command:',
    '  %s %s' % (sys.executable, ' '.join(sys.argv))
)
ASM_BADGE = '; %s\n; %s\n\n' % BADGE
C_BADGE = '/*\n * %s\n * %s\n */\n\n' % BADGE
GEN_BADGE = '# %s\n# %s\n\n' % BADGE

def _get_badge(name):
    _, ext = os.path.splitext(name)
    return {
        '.asm': ASM_BADGE,
        '.generated': GEN_BADGE,
    }.get(ext, C_BADGE)

def write(dir_, name, text, badge=False):
    f = open(os.path.join(dir_, name), "w")
    try:
        if badge:
            f.write(_get_badge(name))
        f.write(text)
    finally:
        f.close()


#==========================================================================

ALL_FILES = object()

def _read_these_files(src, files):
    result = {}
    for info in files:
        name, reader = info[:2]
        extra_args = info[2:]
        key = scrunch_filename(name)
        result[key] = reader(src, name, *extra_args)
    return result

@return_dict('ALL_FILES')
def _read_all_files(src):
    return tuple(
        (scrunch_filename(name), read(src, name))
        for name in os.listdir(src)
        if os.path.isfile(os.path.join(src, name))
    )

def _read_files(src, files):
    if files is ALL_FILES:
        return _read_all_files(src)
    return _read_these_files(src, files)

def _write_files(dir_, files):
    for (path, text) in files.items():
        write(dir_, path, text, badge=True)

def _change_keys(orig, new_keys):
    return dict((name, orig[key]) for (name, key) in new_keys)

def run_generator(cls, input_info, output_names):
    src, dst = sys.argv[1:]
    inputs = _read_files(src, input_info)
    outputs = cls().run(inputs)
    files = _change_keys(outputs, output_names)
    _write_files(dst, files)


#==========================================================================
